#include <BRepLib_MakeWire.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Wire.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <Geom_Plane.hxx>
#include <gp_Ax3.hxx>
#include <gp_Pln.hxx>
#include <ShapeFix_ShapeTolerance.hxx>
#include <ShapeFix_Shape.hxx>
#include <TopoDS.hxx>

#include "CurveEdgePlaneSurfaceHandler.h"
#include "Scene.h"
#include "SendPointHandlerBase.h"
#include "Operation/OpAdd.h"
#include "Surface.h"
#include "SelectHandler3D.h"
#include "OSGNodeMask.h"
#include "Ent.h"
#include "Plane.h"
#include "OcctKit.h"

void addSurface(Scene* scene, std::shared_ptr<Surface>& surface)
{
	auto undoStack = scene->undoStack();
	std::set<std::shared_ptr<INode>> children;
	children.insert(surface);
	undoStack->push(new OpAdd(children));
}

TopoDS_Face makeFaceFromEdges(const std::vector<TopoDS_Edge>& outEdges, const std::vector<std::vector<TopoDS_Edge>>& inEdges, QString& errorString)
{
	TopoDS_Wire outWire;
	bool success = makeWire(outEdges, outWire);
	if (success)
	{
		BRepLib_MakeFace fmaker(outWire, true);
		for (int i = 0; i < inEdges.size(); ++i)
		{
			TopoDS_Wire inWire;			
			const auto& inEdge = inEdges[i];
			bool success = makeWire(inEdge, inWire);
			if(success)
				fmaker.Add(inWire);
		}
		if (fmaker.IsDone())
		{
			ShapeFix_Shape fixer;
			fixer.Init(fmaker.Face());
			fixer.Perform();
			return TopoDS::Face(fixer.Shape());
		}
		else
		{
			errorString = QObject::tr("用首尾相接的曲线环创建有界平面失败");
		}
	}
	else
	{
		errorString = QObject::tr("创建首尾相接的曲线环失败");
	}
	return TopoDS_Face();
}

CurveEdgePlaneSurfaceHandler::CurveEdgePlaneSurfaceHandler()
{
}

CurveEdgePlaneSurfaceHandler::~CurveEdgePlaneSurfaceHandler()
{
}

void CurveEdgePlaneSurfaceHandler::input(const QVariant& data, const QString& rawInput, CommandSource cs)
{
	auto sph = getSendPointHandler();
	auto scene = getScene();
	auto selector = qobject_cast<SelectHandler3D*>(getSelectHandler());
	if (data.type() == QVariant::Bool && !data.toBool())
	{
		selector->clearSelection();
		emit finished();
		return;
	}

	if (status() == 0)
	{
		if (selector)
		{
			selector->clearSelection();
			selector->beginSelect(D2CurveMask | D3CurveMask);
			prompt(1, tr("选择共面的外环曲线: "));
		}
		return;
	}

	if (status() == 1)
	{
		if (selector && selector->done())
		{
			auto selections = selector->selectionSet();
			selector->clearSelection();
			if (selections.size() > 0)
			{
				BRepBuilderAPI_MakeEdge edgeMaker;
				for (auto selection : selections)
				{
					auto curve3d = std::dynamic_pointer_cast<Ent3DCurve>(selection);
					if (curve3d)
					{
						auto curves = curve3d->getCurve3d();
						for (const auto& curve : curves)
						{
							edgeMaker.Init(curve);
							if (edgeMaker.IsDone())
							{
								auto edge = edgeMaker.Edge();
								ShapeFix_ShapeTolerance fixer;
								fixer.SetTolerance(edge, 0.0001, TopAbs_ShapeEnum::TopAbs_VERTEX);
								m_outEdges.push_back(edge);
							}
						}
					}
					else
					{
						auto curve2d = std::dynamic_pointer_cast<Ent2DCurve>(selection);
						if (curve2d)
						{
							auto curves = curve2d->getCurve2d();
							auto parent = curve2d->getParent();
							UCS* ucs = dynamic_cast<UCS*>(parent);
							for (const auto& curve : curves)
							{
								auto curve3d = curves2dTo3d(curve, ucs->getPln());
								edgeMaker.Init(curve3d);
								if (edgeMaker.IsDone())
								{
									auto edge = edgeMaker.Edge();
									ShapeFix_ShapeTolerance fixer;
									fixer.SetTolerance(edge, 0.0001, TopAbs_ShapeEnum::TopAbs_VERTEX);
									m_outEdges.push_back(edge);
								}
							}
						}
					}
				}
				selector->clearSelection();
				selector->beginSelect(D2CurveMask | D3CurveMask);
				prompt(2, tr("选择共面的内环曲线或者<结束命令>: "));
			}
		}
		return;
	}
	if (status() == 2)
	{
		if (selector && selector->done())
		{
			auto selections = selector->selectionSet();
			selector->clearSelection();
			if (selections.size() > 0)
			{
				std::vector<TopoDS_Edge> edges;
				BRepBuilderAPI_MakeEdge edgeMaker;
				for (auto selection : selections)
				{
					auto curve3d = std::dynamic_pointer_cast<Ent3DCurve>(selection);
					if (curve3d)
					{
						auto curves = curve3d->getCurve3d();
						for (const auto& curve : curves)
						{
							edgeMaker.Init(curve);
							if (edgeMaker.IsDone())
							{
								auto edge = edgeMaker.Edge();
								ShapeFix_ShapeTolerance fixer;
								fixer.SetTolerance(edge, 0.0001, TopAbs_ShapeEnum::TopAbs_VERTEX);
								edges.push_back(edge);
							}
						}
					}
					else
					{
						auto curve2d = std::dynamic_pointer_cast<Ent2DCurve>(selection);
						if (curve2d)
						{
							auto curves = curve2d->getCurve2d();
							auto parent = curve2d->getParent();
							UCS* ucs = dynamic_cast<UCS*>(parent);
							for (const auto& curve : curves)
							{
								auto curve3d = curves2dTo3d(curve, ucs->getPln());
								edgeMaker.Init(curve3d);
								if (edgeMaker.IsDone())
								{
									auto edge = edgeMaker.Edge();
									ShapeFix_ShapeTolerance fixer;
									fixer.SetTolerance(edge, 0.0001, TopAbs_ShapeEnum::TopAbs_VERTEX);
									edges.push_back(edge);
								}
							}
						}
					}
				}
				m_inEdges.push_back(edges);
				selector->clearSelection();
				selector->beginSelect(D2CurveMask | D3CurveMask);
				prompt(2, tr("选择共面的内环曲线或者<结束命令>: "));
			}
			else
			{
				QString errorString;
				auto face = makeFaceFromEdges(m_outEdges, m_inEdges, errorString);
				if (face.IsNull())
				{
					remark(errorString);
					emit finished();
					return;
				}
				auto surface = std::make_shared<Surface>(scene);
				surface->setShape(face);
				addSurface(scene, surface);
				emit finished();
				return;
			}
		}
		return;
	}
}
